<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>打开控制台查看结果</div>

    <script>
        console.log('===========剩余运算符=========');
        console.log(...[1,2,3,4,5]);
        /* 剩余运算符如果只有一层，是深拷贝 */
        // 数组
        let a = [1,2,3,4]
        let b = [...a]
        b[0] = 5
        console.log(a);  // [1,2,3,4]
        console.log(b);  // [5,2,3,4]
        // 对象
        let aa = {name:'西方'}
        let bb = {...aa}
        bb.name = '求败'
        console.log(aa);  // {name:'西方'}
        console.log(bb);  // {name:'求败'}


        /* 剩余运算符如果有多层，数据是基本类型的，深拷贝 */
        let c = [1,2,3]
        let d = [4,5,6]
        let e = [...c,...d]
        e[0] = 9
        console.log(c);  // [1, 2, 3]
        console.log(d);  // [4, 5, 6]
        console.log(e);  // [9, 2, 3, 4, 5, 6]

        /* 剩余运算符有多层，数据类型是引用类型，浅拷贝
           内部的引用类型对象其实复制了指针，所以为浅拷贝
           基础类型为深拷贝。
           对象/数组内的变量是引用类型的，为浅拷贝
         */
        let a2 = [{name:'东方'},5]
        let b2 = [...a2]
        b2[0].name = '不败'
        b2[1] = 6
        console.log(a2);  // [{不败},5]
        console.log(b2);  // [{不败},6]

        console.log('=========Array.from()==========');
        /* Array.from()可以将类似数组对象或者可遍历对象转为真正的数组
           并且必须得有length属性才可以转换
        */
       // 错误的
        let ar = { 
            '0' : 'a',
            '1' : 'b',
            '2' : 'c',
        }
        console.log(ar);  // {0: 'a', 1: 'b', 2: 'c'}
        console.log(ar.length); // undefined
        console.log(Array.from(ar));  // []

        // 正确的
        let ar2 = { 
            '0' : 'a',
            '1' : 'b',
            '2' : 'c',
            length : 3
        }
        console.log(ar2);  // {0: 'a', 1: 'b', 2: 'c', length: 3}
        console.log(ar2.length);
        console.log(Array.from(ar2));  // ['a', 'b', 'c']

        /* 任何具有length属性的都可以通过Array.from()转为数组 */
        console.log(Array.from({length : 3}));  // [undefined, undefined, undefined]

        /* Array.from第二个参数可以将转换后的数组中的每个元素进行处理并返回 */
        console.log(Array.from([1,2,3],(x)=> x + 1));  // [2,3,4]
        console.log(Array.from('123',(x)=> x + 1));  // ['11', '21', '31']

        /* Array.from返回的是一个新数组 */
        let arr3 = [1,2,3]
        let arr4 = Array.from(arr3,x => x +1)
        console.log(arr3);  // [1,2,3]
        console.log(arr4);  // [2,3,4]

        /* 通过第二个参数判断数组中的值是否存在，如果数值不存在或者是false（假），则返回0 */
        let arr5 = [1,,2,,3,false,true]
        console.log(Array.from(arr5, n => n || 0));  // [1, 0, 2, 0, 3, 0, true]


        console.log('======Array.fo()======');
        /* 将一组值转换为数组 */
        console.log(Array.of(1,2,3));  //  [1, 2, 3]
        console.log(Array.of(3));  // [3]


        console.log('==========find()、findIndex()、findLast()=========');
        console.log('====find()====');
        /* find()
           数组方法，返回匹配符合条件的第一个数组成员。
        */
       let fi = [
       {id:1,name:'东方'},
       {id:2,name:'不败'},
       {id:3,name:'东方不败'}
       ]
       let back = fi.find(el => el.id == 2)
       let back2 = fi.find(el => el.id == 4)
       console.log(back);  // {id: 2, name: '不败'}
       console.log(back2);  // undefined

       console.log('====findIndex()====');
       /* findIndex()
          数组方法，返回符合条件的数组下标，未找到则返回 -1
          返回的下标从0开始
       */
      let fi2 = [
       {id:1,name:'东方'},
       {id:2,name:'不败'},
       {id:3,name:'东方不败'}
       ]
       let back3 = fi2.findIndex(el => el.id == 2)
       let back4 = fi2.findIndex(el => el.id == 4)
       console.log(back3);  // 1
       console.log(back4);  // -1


       console.log('===findLast()====');
       /* 
       findLast()
       从尾部开始向前检查，返回符合的那一项
        */
       let fi3 = [
       {id:1,name:'东方'},
       {id:2,name:'不败'},
       {id:3,name:'东方不败'}
       ]
       let back5 = fi2.findLast(el => el.id == 2)
       let back6 = fi2.findLast(el => el.id == 4)
       console.log(back5);  // {id: 2, name: '不败'}
       console.log(back6);  // undefined

       console.log('===findLastIndex()====');
       /* 
       findLastIndex()
       从尾部开始向前检查，返回符合的当前项的下标，从0号位开始，未找到返回-1
        */
        let fi4 = [
       {id:1,name:'东方'},
       {id:2,name:'不败'},
       {id:3,name:'东方不败'}
       ]
       let back7 = fi2.findLastIndex(el => el.id == 2)
       let back8 = fi2.findLastIndex(el => el.id == 4)
       console.log(back7);  // 1
       console.log(back8);  // -1

       console.log('=====fill()=====');
       /* fill()
          将给定的参数填充数组
       */
       console.log([1,2,3].fill(5));    // [5,5,5]

       /* 第二个参数和第三个参数分别为填充的开始位置和结束位置的前一位,从0号位开始 */
       console.log([1,2,3,4,5].fill(9,2,4));    // [1, 2, 9, 9, 5]

       console.log('======entries()、keys()、values()=======');
   /* keys对键名遍历 */
    for (let index of ['a', 'b'].keys()) { console.log(index) }  // 0  1
    /* values对键值遍历 */
    for (let index of ['a', 'b'].values()) { console.log(index) } // a  b
    /* entries键值对遍历 */
    for (let [index,item] of ['a', 'b'].entries()) { console.log(index,item) } 
    // 0 'a'
    // 1 'b'

    console.log('==========includes()========');
    /* includes() 判断数组中是否存在对应的值
       返回true和false
    */
   console.log([1,2,3].includes(2));  // true
   console.log([1,2,3].includes(4));  // false

   console.log('==========flat()，flatMap()========');
    /* 
    flat会忽略数组中的空位
    flat返回新数组，不会影响原数组
     */
   /* flat()可以将嵌套数组'拉平'，变成一维数组  */
   console.log([1,2,[3,4]].flat());  //  [1, 2, 3, 4]

   /* flat()的参数代表需要拉平的层数，这里嵌套了3层数组，拉平3层 */
   console.log([1,2,[3,[4,5,[6,7]]]].flat(3));  // [1, 2, 3, 4, 5, 6, 7]

   /* Infinity为深度拉平，不管嵌套多少层都会转换为一维数组  */
   console.log([1,2,[3,[4,5,[6,7]]]].flat(Infinity));  // [1, 2, 3, 4, 5, 6, 7]

   /* flatMap()
      相当于map函数，对数组的每一项进行迭代操作，并返回新数组，不会影响原数组
   */
   console.log([1,2,3].flatMap(el => el + 1));  // [2,3,4]

   console.log('========at()==========');
   /* at()参数为数组的索引
      正数从头部 0 开始
      负数从尾部 -1 开始，-1代表数组尾部的第一个值
   */
  console.log([1,2,3,4,5].at(2));  // 3
  console.log([1,2,3,4,5].at(-2)); // 4
  console.log('hello world'.at(2)); // l
  console.log('hello world'.at(-3)); // r

  /* 超出范围返回undefined */
  console.log([1,2,3,4,5].at(-20)); // undefined
  console.log([1,2,3,4,5].at(20)); // undefined

  console.log('==========toReversed()，toSorted()，toSpliced()，with() ============');
  /* 普通的数组方法例如：push()、pop()、shift()、unshift()这些会影响原数组
     现在有一个提案，对数组进行操作时，不影响原数组，返回一个原数组的的拷贝
     分别有四个：toReversed()，toSorted()，toSpliced()，with()
     这四个方法对应的是原有的方法，用法一模一样，只是不会改变原数组，返回一个新数组
     toReversed()对应reverse()
     toSorted()对应sort()
     toSpliced()对应splice()
     with(index, value)对应splice(index, 1, value)
  */

  console.log('=========group()，groupToMap()=======');
  /* group() 分组函数
     可以将原数组进行分组，并返回分组后的对象
   */
//   let gr = [1,2,3,4,5]
//   let g = gr.group(el=> el > 3 ? 'greater' : 'less')
//   console.log(g);  // { greater: [4,5], less: [1,2,3] }

  /* groupToMap() 分组函数
     相当于map函数，对数组的每一项进行迭代操作，并返回新数组，不会影响原数组
   */


   console.log('=========数组空位========');
   /* 
     数组的空位是指数组的某一个位置没有任何值
   */
  console.log(Array(3));  // [empty x 3]也就是[,,,]
  /* 需要注意的是，空位并不是undefined，某一个位置的值等于undefined，其实是有值的
     空位是没有任何值，in运算符可以直观的看到这一点
  */
 console.log(0 in [undefined,undefined,undefined]);  // true
 console.log(0 in [,,,]);  // false
 /* 上面代码说明，第一个数组的0号位是有值的，第二个数组的0号位没有值的 */


 /* ES5方法对空位的处理有很多不同，但大多数情况下会忽略空位 */
 // forEach(), filter(), reduce(), every() 和some()都会跳过空位。  
 // map()会跳过空位，但会保留这个值
 // join()和toString()会将空位视为undefined，而undefined和null会被处理成空字符串。 

 /* ES6则是将空位转换成undefined，ES6的方法不会忽略空位 */
 console.log(Array.from([1,,3]));  //  [1, undefined, 3]

 console.log(...[1,,3]);  //  1, undefined, 3

 // copyWithin()会连空位一起复制
 console.log([,'a','b',,].copyWithin(2,0));  // [,"a",,"a"]

 // fill会将空位视为正常位
 console.log([4,,6].fill(1));  //  1, 1, 1

 /* entries()、keys()、values()、find()和findIndex()会将空位处理成undefined。 */

 /* js的数组空位处理并不统一，应该避免在数组中出现空位 */

 console.log('=========sort()=========');
 /* sort()排序是数组中一个非常重要的方法 */
 let arr = [2,3,6,4,5,1]
 console.log(arr.sort((a,b) => a - b));  // [1,2,3,4,5,6]
 console.log(arr.sort((a,b) => b - a));  // [6,5,4,3,2,1]

 /* 按条件排序 */
 let arr2 = [{id:1,name:'名称1'},{id:3,name:'名称3'},{id:2,name:'名称2'},{id:6,name:'名称6'},{id:4,name:'名称4'},{id:5,name:'名称5'}]
let so = arr2.sort((a,b)=>{ return a.id - b.id });
console.log(so);
// [{id: 1, name: '名称1'},{id: 2, name: '名称2'},{id: 3, name: '名称3'},{id: 4, name: '名称4'},{id: 5, name: '名称5'},{id: 6, name: '名称6'}]

    
    </script>
</body>
</html>